package com.fwj.user.service.user.rbac;

import com.alibaba.fastjson.JSONObject;
import com.fwj.core.common.common.CommonUtils;
import com.fwj.core.common.constant.DataConstant;
import com.fwj.core.common.execption.CommonException;
import com.fwj.core.common.model.ResponseDTO;
import com.fwj.core.common.model.ResponseEnum;
import com.fwj.user.api.rbac.RBACAuthService;
import com.fwj.user.api.rbac.RBACRoleService;
import com.fwj.user.api.rbac.RBACService;
import com.fwj.user.api.user.UserService;
import com.fwj.user.dao.rbac.RBACRelationAuthAndMenuMapper;
import com.fwj.user.dao.rbac.RBACRelationRoleAndAuthMapper;
import com.fwj.user.dao.rbac.RBACRelationUserAndRoleMapper;
import com.fwj.user.entity.rbac.auth.Auth;
import com.fwj.user.entity.rbac.auth.RBACRelationRoleAndAuth;
import com.fwj.user.entity.rbac.role.RBACRelationUserAndRole;
import com.fwj.user.entity.rbac.role.Role;
import com.fwj.user.entity.user.UserBaseInfo;
import com.fwj.user.model.rbac.role.UserAndRoleVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: fwj
 * @Data: 2022/5/1 17:06
 * @Version 1.0
 * @Description:
 */

@Service
public class RBACServiceImpl implements RBACService {


    //添加日志工厂
    private static final Logger LOGGER = LoggerFactory.getLogger(RBACServiceImpl.class);

    @Autowired
    private RBACRelationUserAndRoleMapper userAndRoleMapper;

    @Autowired
    private RBACRelationRoleAndAuthMapper roleAndAuthMapper;

    @Autowired
    private RBACRelationAuthAndMenuMapper authAndMenuMapper;

    @Autowired
    private RBACRoleService roleService;

    @Autowired
    private RBACAuthService authService;

    @Autowired
    private UserService userService;

    @Override
    @Transactional
    public ResponseDTO bindRoleForUser(UserAndRoleVo userAndRoleVo, UserBaseInfo userBaseInfo) {
        try {
            //查找用户ID和角色ID
            RBACRelationUserAndRole rbacRelationUserAndRole = buildUserAndRoleByNumber(userAndRoleVo);
            rbacRelationUserAndRole.setCreator(userBaseInfo.getId());
            //构建插入实体
            RBACRelationUserAndRole execUserAndRole = buildUserAndRole(rbacRelationUserAndRole);
            //检测该用户是否已关联该角色
            checkAssociated(execUserAndRole);
            //执行插入
            userAndRoleMapper.insertSelective(execUserAndRole);
            return new ResponseDTO().success();
        } catch (Exception e) {
            LOGGER.error(e.toString());
            return new ResponseDTO().fail();
        }
    }

    private RBACRelationUserAndRole buildUserAndRoleByNumber(UserAndRoleVo userAndRoleVo) {
        RBACRelationUserAndRole userAndRole = new RBACRelationUserAndRole();
        //查找用户ID
        Long userId = findUserID(userAndRoleVo);
        userAndRole.setUserId(userId);
        //查找角色ID
        Long roleId = findRoleID(userAndRoleVo);
        userAndRole.setRoleId(roleId);
        return userAndRole;
    }

    private Long findRoleID(UserAndRoleVo userAndRoleVo) {
        Role role = roleService.findRoleByRoleNumber(userAndRoleVo.getRoleNumber());
        return role.getRoleId();
    }

    private Long findUserID(UserAndRoleVo userAndRoleVo) {
        UserBaseInfo userBaseInfo = userService.findUserBaseInfoByUserNumber(userAndRoleVo.getUserNumber());
        return userBaseInfo.getId();
    }

    private RBACRelationUserAndRole buildUserAndRole(RBACRelationUserAndRole userAndRole) {
        RBACRelationUserAndRole retUserAndRole = new RBACRelationUserAndRole();
        retUserAndRole.setRoleId(userAndRole.getRoleId());
        retUserAndRole.setUserId(userAndRole.getUserId());
        retUserAndRole.setCreator(userAndRole.getCreator());
        retUserAndRole.setCreateTime(LocalDateTime.now());
        retUserAndRole.setUpdateTime(LocalDateTime.now());
        retUserAndRole.setStatus(DataConstant.NORMAL);
        return retUserAndRole;
    }

    private void checkAssociated(RBACRelationUserAndRole execUserAndRole) throws Exception{
        //构建Example
        Example example = buildUserAndRoleExample(execUserAndRole);
        List<RBACRelationUserAndRole> userAndRoleList = userAndRoleMapper.selectByExample(example);
        //如果已关联则抛出异常
        if (userAndRoleList.size() > 0){
            LOGGER.error("该用户已关联该角色");
            throw new CommonException(ResponseEnum.USER_ROLE_ASSOCIATED);
        }
    }

    private Example buildUserAndRoleExample(RBACRelationUserAndRole execUserAndRole) {
        Example example = new Example(RBACRelationUserAndRole.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("userId",execUserAndRole.getUserId());
        criteria.andEqualTo("roleId",execUserAndRole.getRoleId());
        criteria.andEqualTo("status",DataConstant.NORMAL);
        return example;
    }

    @Override
    public ResponseDTO queryRoleListByUser(UserBaseInfo userBaseInfo) {
        try {
            //查询用户具有的角色
            List<RBACRelationUserAndRole> userAndRoleList = userAndRoleMapper.findRoleListByUserId(userBaseInfo.getId(),DataConstant.NORMAL);
            //根据角色ID查询角色
            List<Role> roleList = buildRoleList(userAndRoleList);
            return new ResponseDTO().success().setData(roleList);
        } catch (Exception e) {
            LOGGER.error(e.toString());
            return new ResponseDTO().fail();
        }
    }

    private List<Role> buildRoleList(List<RBACRelationUserAndRole> userAndRoleList) {
        try {
            //构建RoleId列表
            List<Long> roleIdList = new ArrayList<>();
            for (RBACRelationUserAndRole userAndRole : userAndRoleList){
                roleIdList.add(userAndRole.getRoleId());
            }
            //tkMapper批量查询，实际底层源码是构建动态IN，因此对于一千个以上的数据列不适用
            return roleService.findRoleListByRoleId(roleIdList);
        } catch (Exception e) {
            LOGGER.error(e.toString());
            throw new CommonException(ResponseEnum.SERVER_ERROR);
        }
    }

    @Override
    public ResponseDTO queryRelationUserAndRole(UserAndRoleVo userAndRoleVo) {
        try {
            //查找用户ID和角色ID
            RBACRelationUserAndRole rbacRelationUserAndRole = buildUserAndRoleByNumber(userAndRoleVo);
            Example example = buildUserAndRoleExample(rbacRelationUserAndRole);
            RBACRelationUserAndRole ret = userAndRoleMapper.selectOneByExample(example);
            if (CommonUtils.isEmpty(ret)){
                LOGGER.error("角色未关联");
                throw new CommonException(ResponseEnum.USER_ROLE_NO_ASSOCIATE);
            }
            return new ResponseDTO().success(ResponseEnum.USER_ROLE_ASSOCIATED);
        } catch (CommonException e){
            return new ResponseDTO().fail(e.getResponseEnum());
        } catch (Exception e) {
            LOGGER.error(e.toString());
            return new ResponseDTO().fail();
        }
    }

    @Override
    public JSONObject queryRelationUserAndAuth(Long userNumber, String authNumber) {
        try {
            //根据权限编码查询权限详情
            Auth auth = authService.findAuthByAuthNumber(authNumber);
            //根据用户编码查找用户信息
            UserBaseInfo userBaseInfo = userService.findUserBaseInfoByUserNumber(userNumber);
            //查询权限编码的查询绑定角色
            RBACRelationRoleAndAuth roleAndAuth = new RBACRelationRoleAndAuth();
            roleAndAuth.setAuthId(auth.getAuthId());
            Example example = buildRoleAndAuthExample(roleAndAuth);
            List<RBACRelationRoleAndAuth> roleAndAuthList = roleAndAuthMapper.selectByExample(example);
            if (CommonUtils.isEmpty(roleAndAuthList)){
                throw new CommonException(ResponseEnum.USER_AUTH_NO_ASSOCIATE);
            }
            //查询用户是否具有上面的角色列表之一的角色或父级角色
            if (!matcherUserIdAndRoleIdList(
                    roleAndAuthList.stream().map(RBACRelationRoleAndAuth::getRoleId).collect(Collectors.toList()),
                    userBaseInfo
            )){
                return new ResponseDTO<>().success(ResponseEnum.USER_AUTH_NO_ASSOCIATE);
            }
            return new ResponseDTO<>().success(ResponseEnum.USER_AUTH_ASSOCIATED);
        } catch (CommonException e){
            LOGGER.error(e.toString());
            return new ResponseDTO<>().fail(e.getResponseEnum());
        } catch (Exception e) {
            LOGGER.error(e.toString());
            return new ResponseDTO<>().fail();
        }
    }

    private boolean matcherUserIdAndRoleIdList(List<Long> roleIdList, UserBaseInfo userBaseInfo) {
        try {
            //构建Example
            Example example = new Example(RBACRelationUserAndRole.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("status",DataConstant.NORMAL);
            criteria.andEqualTo("userId",userBaseInfo.getId());
            if (CommonUtils.isNotEmpty(roleIdList)){
                criteria.andIn("roleId",roleIdList);
            }
            //循环查询用户是否具有该角色或者其父级角色
            for (Long roleId : roleIdList){
                List<RBACRelationUserAndRole> userAndRoleList = userAndRoleMapper.findAllFatherRoleByParentIdByUserId(userBaseInfo.getId(),roleId);
                if (userAndRoleList.size() > 0){
                    return true;
                }
            }
            return false;
        } catch (Exception e) {
            LOGGER.error(e.toString());
            throw new CommonException(ResponseEnum.SERVER_ERROR);
        }
    }

    private Example buildRoleAndAuthExample(RBACRelationRoleAndAuth roleAndAuth) {
        Example example = new Example(RBACRelationRoleAndAuth.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("authId",roleAndAuth.getAuthId());
        criteria.andEqualTo("status",DataConstant.NORMAL);
        return example;
    }

    @Override
    @Transactional
    public ResponseDTO unBindRoleWithUser(UserAndRoleVo userAndRoleVo) {
        try {
            //查找用户ID和角色ID
            RBACRelationUserAndRole rbacRelationUserAndRole = buildUserAndRoleByNumber(userAndRoleVo);
            //构建插入实体
            RBACRelationUserAndRole execUserAndRole = buildUserAndRole(rbacRelationUserAndRole);
            //检测该用户是否已关联该角色
            checkAssociated(execUserAndRole);
            //处理更新实体
            execUserAndRole.setStatus(DataConstant.DELETED);
            execUserAndRole.setCreateTime(null);
            Example example = buildUserAndRoleExample(execUserAndRole);
            userAndRoleMapper.updateByExampleSelective(execUserAndRole,example);
            return new ResponseDTO().success();
        } catch (Exception e) {
            LOGGER.error(e.toString());
            throw new CommonException(ResponseEnum.SERVER_ERROR);
        }
    }

    @Override
    public ResponseDTO queryRoleAssociatedPermissionsList() {
        try {
            return null;
        } catch (Exception e) {
            LOGGER.error(e.toString());
            throw new CommonException(ResponseEnum.SERVER_ERROR);
        }
    }


}
